﻿using System;
using System.IO;
using System.Diagnostics;

using Commons = NougakudoCompanion.Commons;

namespace NougakuDoController
{
    public static class UnZipUtility
    {
        // This constant is debug perpose for shell object as dynamic.
        //const int FOR_SILENT = 0x0004;
        //const int FOR_NOCONFIRMATION = 0x0010;
        //const int FOR_NORERROR_UI = 0x0400;
        //const int FOR_NOCONFIRMMKDIR = 0x0200;
        //const int FOR_NO_UI = FOR_SILENT | FOR_NOCONFIRMATION | FOR_NORERROR_UI | FOR_NOCONFIRMMKDIR;
        //const int FOR_DOWNLOAD = FOR_SILENT | FOR_NOCONFIRMATION;   // for customize flags for download

        const int SLEEP_WAIT = 1000;

        /// <summary>
        /// Extract zip archive file.
        /// If zip include a top folder name as zip file name, extract the include items only.
        /// Else extract all items.
        /// </summary>
        /// <param name="zipFileName">Zip file name of full path </param>
        /// <param name="folderName">Copy folder of full path</param>
        /// <returns>string is errror message</returns>
        static internal Tuple<bool, string> UnZip(string zipFileName, string folderName, Commons.Runtime runtime)
        {
            var errorMsg = "";
            try
            {
#if DEBUG
                Logging.Write("UnZipUtility start from {0} to {1}", new object[] { zipFileName, folderName }, Logging.LogType.INFO);
#endif
                if (!File.Exists(zipFileName))
                {
                    errorMsg = "UnZipUtility not found " + zipFileName + ".";
                    Logging.Write(errorMsg, Logging.LogType.ERROR);
                    return new Tuple<bool,string>(false, errorMsg);
                }
                var ret = CheckDestinationFolder(folderName);
                if (!ret.Item1) return new Tuple<bool,string>(false, ret.Item2);

                var extractInfo = new ProcessStartInfo(
                    System.Environment.ExpandEnvironmentVariables(@"%SystemRoot%\SYstem32\cscript.exe"));
                extractInfo.UseShellExecute = false;
                extractInfo.RedirectStandardInput = true;
                extractInfo.RedirectStandardOutput = true;
                extractInfo.WorkingDirectory = System.Environment.CurrentDirectory;
                // Arguments 1.cscript option as /B /Nologo
                //           2.script file
                //           3.zip file
                //           4.target folder
                //           5.filter folder as folder's items extract. not include folder name. 
                extractInfo.Arguments =
                    @"/B /Nologo " + "\"" + 
                    Path.Combine(runtime.Environment.RuntimeFolder, Commons.Constants.EXTRACT_SCRIPT) + "\" \"" +
                    zipFileName + "\" \"" +
                    folderName + "\" \"" + Path.GetFileName(folderName) + "\"";

                // Change temp folder setting;
                extractInfo.EnvironmentVariables["TEMP"] = runtime.Environment.TempFolder;
                extractInfo.EnvironmentVariables["TMP"] = runtime.Environment.TempFolder;

#if DEBUG
                Logging.Write("UnZipUtility unzip args={0}", new object[] { extractInfo.Arguments }, Logging.LogType.INFO);
#endif

                try
                {
                    var extractProcess = new Process();
                    extractProcess.StartInfo = extractInfo;
                    extractProcess.OutputDataReceived += new DataReceivedEventHandler(extractProcess_OutputDataReceived);
                    extractProcess.Start();
                    extractProcess.BeginOutputReadLine();
                    extractProcess.WaitForExit();
                    if (extractProcess.ExitCode != 0)
                    {
                        Logging.Write("UnZipUtility script error.", Logging.LogType.ERROR);
                        return new Tuple<bool, string>(false, "UnZipUtility script error.");
                    }
                    extractProcess.Close();
                    //System.Threading.Thread.Sleep(SLEEP_WAIT);
                    return new Tuple<bool,string>(true, "");
                }
                catch (Exception e)
                {
                    errorMsg = "UnZipUtility error : " + e.Message;
                    Logging.Write(errorMsg, Logging.LogType.ERROR);
                    return new Tuple<bool,string>(false, errorMsg);
                }

            }
            catch (Exception e)
            {
                errorMsg = "UnZipUtility error " + e.Message + ".";
                Logging.Write(errorMsg, Logging.LogType.ERROR);
                return new Tuple<bool,string>(false, errorMsg);
            }

        }

        static void extractProcess_OutputDataReceived(object sender, DataReceivedEventArgs e)
        {
            Logging.Write("UnZipUtility running.. {0}", new object[] { e.Data }, Logging.LogType.INFO);
        }



        static Tuple<bool, string> CheckDestinationFolder(string folderName)
        {
            string errorMsg = "UnZipUtility timeout.";
            // retry delete, if during used directory.
            for (var i = 0; i < Commons.Constants.DELETE_RETRY_COUNT; i++)
            {
                try
                {
                    if (!Directory.Exists(folderName))
                    {
                        Directory.CreateDirectory(folderName);
#if DEBUG
                        Logging.Write("UnZipUtility create folder : {0}", new object[] { folderName }, Logging.LogType.INFO);
#endif
                    }
                    else
                    {
                        Directory.Delete(folderName, true);
                        Directory.CreateDirectory(folderName);
#if DEBUG
                        Logging.Write("UnZipUtility deleted and created folder : {0}", new object[] { folderName }, Logging.LogType.INFO);
#endif
                    }
                    return new Tuple<bool,string>(true, "");
                }
                catch (Exception e)
                {
                    Logging.Write("UnZipUtility retry. For {0}", new object[] { e.Message }, Logging.LogType.WARNING);
                    System.Threading.Thread.Sleep(SLEEP_WAIT);
                }
            }
            Logging.Write(errorMsg, Logging.LogType.ERROR);
            return new Tuple<bool,string>(false, errorMsg);

        }

//        This method is debug perpose for shell object as dynamic.
//        static dynamic GetRootFolder(dynamic zipFolder, string zipFileName)
//        {
//            var folder = Path.GetFileNameWithoutExtension(zipFileName).ToLower();
//            foreach (dynamic item in zipFolder.Items)
//            {
//                try
//                {
//#if DEBUG
//                    Logging.Write("UnZipUtility filter " + item.ToString(), Logging.LogType.WARNING);
//#endif
//                    // item.Name
//                    if (((string)item.Name).ToLower() == folder)
//                    {
//#if DEBUG
//                        Logging.Write("UnZipUtility filter Ok={0}", new object[]{folder}, Logging.LogType.INFO);
//#endif
//                        return item;
//                    }
//                }
//                catch (Exception e)
//                {
//                    Logging.Write("UnZipUtility GetRootFolder : {0}", new object[] { e.Message }, Logging.LogType.WARNING);
//                }

//            }
//            return null;
//        }

        /// <summary>
        /// This method is debug perpose for shell object as dynamic.
        /// This method is test purpose for development fabric.
        /// Don't use on Windows Azure Role instance. Because not running CopyHere method of dynamic.
        /// </summary>
        /// <param name="zipFileName"></param>
        /// <param name="folderName"></param>
        /// <param name="runtime"></param>
        /// <returns>string is error message</returns>
//        static internal Tuple<bool, string> UnZipForDevFabric(string zipFileName, string folderName, Commons.Runtime runtime)
//        {
//            var errorMsg = "";
//            try
//            {
//#if DEBUG
//                Logging.Write("UnZipUtility start unZipDevFabrc {0} to {1}", new object[] { zipFileName, folderName }, Logging.LogType.INFO);
//#endif
//                if (!File.Exists(zipFileName))
//                {
//                    errorMsg = "UnZipUtility not found " + zipFileName + " .";
//                    Logging.Write(errorMsg, Logging.LogType.ERROR);
//                    return new Tuple<bool,string>(false, errorMsg);
//                }
//                var ret = CheckDestinationFolder(folderName);
//                if (!ret.Item1) return ret;


//                dynamic shellApp = Activator.CreateInstance(Type.GetTypeFromProgID("Shell.Application"));
//                dynamic sourceFolder = shellApp.NameSpace(zipFileName);
//                dynamic destinationFolder = shellApp.NameSpace(folderName);
//                Logging.Write("UnZipUtility filter check", Logging.LogType.INFO);

//                dynamic filter = GetRootFolder(shellApp.NameSpace(zipFileName), zipFileName);
//#if DEBUG
//                Logging.Write("UnZipUtility filter check after", Logging.LogType.INFO);
//#endif
//                if (filter == null)
//                {
//                    //destinationFolder.CopyHere(sourceFolder.Items, FOR_NOCONFIRMATION);
//#if DEBUG
//                    Logging.Write("UnZipUtility filter nothing", Logging.LogType.INFO);
//#endif
//                    destinationFolder.CopyHere(sourceFolder.Items, FOR_DOWNLOAD);
//                }
//                else
//                {
//                    var folder = filter.GetFolder();    // cast FolderItem to Folder
//#if DEBUG
//                    Logging.Write("UnZipUtility filter apply", Logging.LogType.INFO);
//#endif
//                    //destinationFolder.CopyHere(folder.Items, FOR_NOCONFIRMATION);
//                    destinationFolder.CopyHere(folder.Items, FOR_DOWNLOAD);
//                }
//                return new Tuple<bool,string>(true, "");
//            }
//            catch (Exception e)
//            {
//                errorMsg = "UnZipUtility error " + e.Message + ".";
//                Logging.Write(errorMsg, Logging.LogType.ERROR);
//                return new Tuple<bool,string>(false, errorMsg);
//            }

//        }

    }


}
